package com.oanda.blackberry.restapi;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;

import javax.microedition.io.ConnectionNotFoundException;
import javax.microedition.io.HttpConnection;
import javax.microedition.io.HttpsConnection;
import javax.microedition.pki.CertificateException;

import net.rim.device.api.util.Persistable;

import com.oanda.blackberry.net.AutoConnectionManager;
import com.oanda.blackberry.net.RestException;
import com.oanda.blackberry.util.log.Logger;

public class Rest implements Persistable {
    String response = "";
    String errorMessage = "";
    boolean error = false;
    public static final String GET = "GET";
    public static final String POST = "POST";

    public String proceedConnection(HttpConnection connection) throws IOException, RestException {
        int responseCode = connection.getResponseCode();
        String responseMessage = connection.getResponseMessage();
        Logger.log(String.valueOf(responseCode) + responseMessage);

        if (responseCode == 200) {
            InputStream inputstream = connection.openInputStream();
            int length = (int) connection.getLength();
            if (length != -1) {
                byte[] incomingData = new byte[length];
                inputstream.read(incomingData);
                String receivedText = new String(incomingData);

                if (inputstream != null)
                    inputstream.close();
                if (connection != null)
                    connection.close();

                return receivedText;
            }
            ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
            int ch;
            while ((ch = inputstream.read()) != -1) {
                bytestream.write(ch);
            }
            String receivedText = new String(bytestream.toByteArray());
            bytestream.close();

            if (inputstream != null) {
                inputstream.close();
            }
            if (connection != null)
                connection.close();

            return bytestream.toString();
        }

        throw new RestException(String.valueOf(responseCode) + ": " + responseMessage);
    }

    public String proceedConnection(String url) throws RestException {
        HttpsConnection connection = null;
        InputStream inputstream = null;
        OutputStream outputstream = null;

        int responseCode = 0;
        String responseMessage = "";

        this.error = false;
        this.errorMessage = "";
        this.response = "";
        try {
            Logger.log(url);
            Logger.log("connecting");

            connection = AutoConnectionManager.request(url);

            if (connection == null) {
                this.error = true;
                this.errorMessage = "Unable to open connection.";
            } else {
                Logger.log("opened");

                connection.setRequestMethod("GET");
                connection.setRequestProperty("User-Agent",
                        "Profile/MIDP-2.0 Configuration/CLDC-1.0");
                connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                connection.setRequestProperty("Connection", "Keep-Alive");

                Logger.log("set requested properties and waiting reponse code");

                responseCode = connection.getResponseCode();
                responseMessage = connection.getResponseMessage();
                Logger.log(String.valueOf(responseCode) + responseMessage);

                Logger.log("waiting input stream...");
                inputstream = connection.openInputStream();

                if ((responseCode == 200) || (isError(responseCode))) {
                    int length = (int) connection.getLength();

                    if (length != -1) {
                        byte[] incomingData = new byte[length];
                        inputstream.read(incomingData);
                        String receivedText = new String(incomingData);
                        this.response = receivedText;
                    } else {
                        ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
                        int ch;
                        while ((ch = inputstream.read()) != -1) {
                            bytestream.write(ch);
                        }
                        String receivedText = new String(bytestream.toByteArray());
                        bytestream.close();

                        this.response = bytestream.toString();
                    }
                } else {
                    Logger.log(String.valueOf(responseCode) + ":" + responseMessage);
                    this.error = true;
                    this.errorMessage = (String.valueOf(responseCode) + ": " + responseMessage);
                }
            }
        } catch (InterruptedIOException io) {
            this.error = true;
            this.errorMessage += "InterruptedIOException: ";
            this.errorMessage += io.getMessage();
            Logger.log("InterruptedIOException: " + io.getMessage());
        } catch (ConnectionNotFoundException cn) {
            this.error = true;
            this.errorMessage += "ConnectionNotFoundException: ";
            this.errorMessage += cn.getMessage();
            Logger.log("ConnectionNotFoundException: " + cn.getMessage());
        } catch (CertificateException ce) {
            this.error = true;
            this.errorMessage += "CertificateException: ";
            this.errorMessage += ce.getMessage();
            this.errorMessage += " ";
            this.errorMessage += String.valueOf(ce.getReason());
            Logger.log("CertificateException: " + ce.getMessage());
        } catch (IOException io) {
            this.error = true;
            this.errorMessage += "IOException: ";
            this.errorMessage += io.getMessage();
            Logger.log("IOException: " + io.getMessage());
        } catch (Exception e) {
            this.error = true;
            this.errorMessage += "Exception: ";
            this.errorMessage += e.getMessage();
            Logger.log("Exception: " + e.getMessage());
        } catch (Throwable t) {
            this.error = true;
            this.errorMessage += "Throwable: ";
            this.errorMessage += t.getMessage();
            Logger.log("Throable(Serious rest exception) : " + t.getMessage());
        } finally {
            try {
                if (inputstream != null) {
                    inputstream.close();
                    Logger.log("inpustream closed");
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
                Logger.log("error in closing input stream");
            }
            try {
                if (outputstream != null) {
                    outputstream.close();
                    Logger.log("outputstream closed");
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
                Logger.log("login.json: error in closing output stream");
            }
            try {
                if (connection != null) {
                    connection.close();
                    Logger.log("connections closed");
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
                Logger.log("login.json: error in closing connections");
            }
        }

        if (this.error) {
            Logger.log("response code: " + String.valueOf(responseCode) + " response message: "
                    + (responseMessage == null ? "" : responseMessage) + " error message: "
                    + this.errorMessage + (this.response == null ? "" : this.response));

            throw new RestException(this.errorMessage
                    + (this.response == null ? "" : this.response), responseCode, responseMessage,
                    this.response);
        }

        Logger.log("" + this.response);

        return this.response;
    }

    public String proceedConnection(String url, String encodedData) throws RestException {
        HttpsConnection connection = null;
        InputStream inputstream = null;
        OutputStream outputstream = null;

        int responseCode = 0;
        String responseMessage = "";

        this.error = false;
        this.errorMessage = "";
        this.response = "";
        try {
            Logger.log(url);
            Logger.log(encodedData);
            Logger.log("connecting");
            connection = AutoConnectionManager.request(url);

            if (connection == null) {
                this.error = true;
                this.errorMessage = "Unable to open connection.";
            } else {
                connection.setRequestMethod("POST");
                connection.setRequestProperty("User-Agent",
                        "Profile/MIDP-2.0 Configuration/CLDC-1.0");
                connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                connection.setRequestProperty("Connection", "Keep-Alive");
                connection.setRequestProperty("Content-Length",
                        String.valueOf(encodedData.length()));

                outputstream = connection.openOutputStream();
                outputstream.write(encodedData.getBytes());
                outputstream.flush();

                responseCode = connection.getResponseCode();
                responseMessage = connection.getResponseMessage();

                inputstream = connection.openInputStream();

                if ((responseCode == 200) || (isError(responseCode))) {
                    int length = (int) connection.getLength();
                    if (length != -1) {
                        byte[] incomingData = new byte[length];
                        inputstream.read(incomingData);
                        String receivedText = new String(incomingData);
                        this.response = receivedText;
                    } else {
                        ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
                        int ch;
                        while ((ch = inputstream.read()) != -1) {
                            bytestream.write(ch);
                        }
                        String receivedText = new String(bytestream.toByteArray());
                        bytestream.close();

                        this.response = bytestream.toString();
                    }
                } else {
                    Logger.log(String.valueOf(responseCode) + ":" + responseMessage);
                    this.error = true;
                    this.errorMessage = (String.valueOf(responseCode) + ": " + responseMessage);
                }
            }
        } catch (InterruptedIOException io) {
            this.error = true;
            this.errorMessage += "InterruptedIOException: ";
            this.errorMessage += io.getMessage();
            Logger.log("InterruptedIOException: " + io.getMessage());
        } catch (ConnectionNotFoundException cn) {
            this.error = true;
            this.errorMessage += "ConnectionNotFoundException: ";
            this.errorMessage += cn.getMessage();
            Logger.log("ConnectionNotFoundException: " + cn.getMessage());
        } catch (CertificateException ce) {
            this.error = true;
            this.errorMessage += "CertificateException: ";
            this.errorMessage += ce.getMessage();
            this.errorMessage += " ";
            this.errorMessage += String.valueOf(ce.getReason());
            Logger.log("CertificateException: " + ce.getMessage());
        } catch (IOException io) {
            this.error = true;
            this.errorMessage += "IOException: ";
            this.errorMessage += io.getMessage();
            Logger.log("IOException: " + io.getMessage());
        } catch (Exception e) {
            this.error = true;
            this.errorMessage += "Exception: ";
            this.errorMessage += e.getMessage();
            Logger.log("Exception: " + e.getMessage());
        } catch (Throwable t) {
            this.error = true;
            this.errorMessage += "Throwable: ";
            this.errorMessage += t.getMessage();
            Logger.log("Throable(Serious rest exception) : " + t.getMessage());
        } finally {
            try {
                if (inputstream != null) {
                    inputstream.close();
                    Logger.log("inpustream closed");
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
                Logger.log("error in closing input stream");
            }
            try {
                if (outputstream != null) {
                    outputstream.close();
                    Logger.log("outputstream closed");
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
                Logger.log("login.json: error in closing output stream");
            }
            try {
                if (connection != null) {
                    connection.close();
                    Logger.log("connections closed");
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
                Logger.log("login.json: error in closing connections");
            }
        }

        if (this.error) {
            Logger.log("response code: " + String.valueOf(responseCode) + " response message: "
                    + (responseMessage == null ? "" : responseMessage) + " error message: "
                    + this.errorMessage + (this.response == null ? "" : this.response));

            throw new RestException(this.errorMessage
                    + (this.response == null ? "" : this.response), responseCode, responseMessage,
                    this.response);
        }

        Logger.log("" + this.response);

        return this.response;
    }

    public Object proceedConnectionToByteArray(String url) throws RestException {
        HttpsConnection connection = null;
        InputStream inputstream = null;
        OutputStream outputstream = null;

        int responseCode = 0;
        String responseMessage = "";

        this.error = false;
        this.errorMessage = "";
        this.response = "";
        try {
            Logger.log(url);
            Logger.log("connecting");

            connection = AutoConnectionManager.request(url);

            if (connection == null) {
                this.error = true;
                this.errorMessage = "Unable to open connection.";
            } else {
                Logger.log("opened");

                connection.setRequestMethod("GET");
                connection.setRequestProperty("User-Agent",
                        "Profile/MIDP-2.0 Configuration/CLDC-1.0");
                connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                connection.setRequestProperty("Connection", "Keep-Alive");

                Logger.log("set requested properties and waiting reponse code");

                responseCode = connection.getResponseCode();
                responseMessage = connection.getResponseMessage();
                Logger.log(String.valueOf(responseCode) + responseMessage);

                Logger.log("waiting input stream...");
                inputstream = connection.openInputStream();

                if ((responseCode == 200) || (isError(responseCode))) {
                    ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
                    int ch;
                    while ((ch = inputstream.read()) != -1) {
                        bytestream.write(ch);
                    }

                    this.response = bytestream.toString();
                    bytestream.close();
                    byte[] arrayOfByte = bytestream.toByteArray();

                    return arrayOfByte;
                }

                Logger.log(String.valueOf(responseCode) + ":" + responseMessage);
                this.error = true;
                this.errorMessage = (String.valueOf(responseCode) + ": " + responseMessage);
            }

        } catch (InterruptedIOException io) {
            this.error = true;
            this.errorMessage += "InterruptedIOException: ";
            this.errorMessage += io.getMessage();
            Logger.log("InterruptedIOException: " + io.getMessage());
        } catch (ConnectionNotFoundException cn) {
            this.error = true;
            this.errorMessage += "ConnectionNotFoundException: ";
            this.errorMessage += cn.getMessage();
            Logger.log("ConnectionNotFoundException: " + cn.getMessage());
        } catch (CertificateException ce) {
            this.error = true;
            this.errorMessage += "CertificateException: ";
            this.errorMessage += ce.getMessage();
            this.errorMessage += " ";
            this.errorMessage += String.valueOf(ce.getReason());
            Logger.log("CertificateException: " + ce.getMessage());
        } catch (IOException io) {
            this.error = true;
            this.errorMessage += "IOException: ";
            this.errorMessage += io.getMessage();
            Logger.log("IOException: " + io.getMessage());
        } catch (Exception e) {
            this.error = true;
            this.errorMessage += "Exception: ";
            this.errorMessage += e.getMessage();
            Logger.log("Exception: " + e.getMessage());
        } catch (Throwable t) {
            this.error = true;
            this.errorMessage += "Throwable: ";
            this.errorMessage += t.getMessage();
            Logger.log("Throable(Serious rest exception) : " + t.getMessage());
        } finally {
            try {
                if (inputstream != null) {
                    inputstream.close();
                    Logger.log("inpustream closed");
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
                Logger.log("error in closing input stream");
            }
            try {
                if (outputstream != null) {
                    outputstream.close();
                    Logger.log("outputstream closed");
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
                Logger.log("login.json: error in closing output stream");
            }
            try {
                if (connection != null) {
                    connection.close();
                    Logger.log("connections closed");
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
                Logger.log("login.json: error in closing connections");
            }
        }

        if (this.error) {
            Logger.log("response code: " + String.valueOf(responseCode) + " response message: "
                    + (responseMessage == null ? "" : responseMessage) + " error message: "
                    + this.errorMessage + (this.response == null ? "" : this.response));

            throw new RestException(this.errorMessage
                    + (this.response == null ? "" : this.response), responseCode, responseMessage,
                    this.response);
        }

        return this.response;
    }

    boolean isError(int responseCode) {
        if ((responseCode == 400) || (responseCode == 401) || (responseCode == 403)
                || (responseCode == 500) || (responseCode == 404)) {
            this.error = true;
            return true;
        }
        return false;
    }
}
